package cn.sylinx.hbatis.ext.starter.springboot;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.core.env.Environment;

import cn.sylinx.hbatis.db.dialect.DbType;
import cn.sylinx.hbatis.ds.DataSourceWrapper;
import cn.sylinx.hbatis.ext.mirage.plugin.SqlResourcePreloadPlugin;
import cn.sylinx.hbatis.ext.xmapper.plugin.XmapperPlugin;
import cn.sylinx.hbatis.kit.StrKit;
import cn.sylinx.hbatis.log.GLog;
import cn.sylinx.hbatis.plugin.IPlugin;
import cn.sylinx.hbatis.plugin.PluginStarter;
import cn.sylinx.hbatis.plugin.datasource.DataSourcePlugin;
import cn.sylinx.hbatis.plugin.ehcache.EhcachePlugin;
import cn.sylinx.hbatis.plugin.model.ModelPreloadPlugin;
import cn.sylinx.hbatis.plugin.proxy.ProxyPlugin;
import cn.sylinx.hbatis.plugin.transaction.TransactionIsolationPlugin;

class HbatisWithCurrentDatasourceInitializationBean {

	public PluginStarter init(DataSource dataSource, Environment env) {
		String dbtype = env.getProperty("hbatis.ds.dbtype", DbType.MYSQL.getValue());
		// 手动初始化数据源
		PluginStarter ps = new PluginStarter();
		DataSourcePlugin dsp = new DataSourcePlugin();
		dsp.setDataSourceWrapper(DataSourceWrapper.create(dataSource, DbType.getDbType(dbtype)));

		ArrayList<IPlugin> pluginList = new ArrayList<>();
		pluginList.add(dsp);

		IPlugin initXmapperPlugin = initXmapperPlugin(env);
		if (initXmapperPlugin != null) {
			pluginList.add(initXmapperPlugin);
		}
		IPlugin initModelPreLoadPlugin = initModelPreLoadPlugin(env);
		if (initModelPreLoadPlugin != null) {
			pluginList.add(initModelPreLoadPlugin);
		}

		IPlugin initEhcachePlugin = initEhcachePlugin(env);
		if (initEhcachePlugin != null) {
			pluginList.add(initEhcachePlugin);
		}

		IPlugin initSqlResourcePreloadPlugin = initSqlResourcePreloadPlugin(env);
		if (initSqlResourcePreloadPlugin != null) {
			pluginList.add(initSqlResourcePreloadPlugin);
		}

		IPlugin initTransactionPlugin = initTransactionPlugin(env);
		if (initTransactionPlugin != null) {
			pluginList.add(initTransactionPlugin);
		}

		IPlugin initProxyPlugin = initProxyPlugin(env);
		if (initProxyPlugin != null) {
			pluginList.add(initProxyPlugin);
		}

		ps.setPluginList(pluginList);
		ps.start();
		GLog.info("hbatis已使用第三方数据源，数据库类型：" + dbtype);
		return ps;
	}

	// 初始化代理插件
	private IPlugin initProxyPlugin(Environment env) {

		// TransactionIsolationPlugin
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.proxy.");
		String clzList = propertyResolver.getProperty("class");
		if (StrKit.isBlank(clzList)) {
			return null;
		}

		ProxyPlugin plugin = new ProxyPlugin();
		String[] clzArray = clzList.split(",");
		for (String clz : clzArray) {
			if (StrKit.isNotBlank(clz)) {
				IPlugin item = null;
				try {
					item = (IPlugin) Class.forName(clz.trim()).newInstance();
				} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
					GLog.error("初始化插件失败, clz: " + clz, e);
				}
				if (item != null) {
					// 加入代理插件
					plugin.addPlugin(item);
				}
			}
		}

		return plugin;
	}

	/**
	 * 初始化xmapper插件
	 * 
	 * @param env
	 */
	private IPlugin initXmapperPlugin(Environment env) {

		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.xmapper.");
		String inited = propertyResolver.getProperty("inited");
		if (!"true".equalsIgnoreCase(inited)) {
			return null;
		}
		GLog.debug("XmapperPlugin inited.");
		// 初始化
		String resourcePath = propertyResolver.getProperty("resourcePath");
		if (resourcePath == null || "".equals(resourcePath)) {
			resourcePath = "xmapper";
		}
		GLog.debug("XmapperPlugin resourcePath:{}", resourcePath);

		XmapperPlugin xmapperPlugin = new XmapperPlugin(resourcePath);
		return xmapperPlugin;
	}

	/**
	 * 初始化modelpreload插件
	 * 
	 * @param env
	 */
	private IPlugin initModelPreLoadPlugin(Environment env) {
		// scanPackageList

		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.modelpreload.");
		String inited = propertyResolver.getProperty("inited");
		if (!"true".equalsIgnoreCase(inited)) {
			return null;
		}

		GLog.debug("ModelPreloadPlugin inited.");

		ModelPreloadPlugin mp = new ModelPreloadPlugin();

		String acmStrategy = propertyResolver.getProperty("acmStrategy");
		if (StrKit.isNotBlank(acmStrategy)) {
			// 设置全局模型字段映射策略
			mp.setAcmStrategyClass(acmStrategy);
		}

		String scanPackageList = propertyResolver.getProperty("scanPackageList");
		if (StrKit.isNotBlank(scanPackageList)) {
			GLog.debug("ModelPreloadPlugin scanPackageList:{}", scanPackageList);
			String[] pkgArray = scanPackageList.split(",");
			mp.setScanPackageList(Arrays.asList(pkgArray));
		}

		return mp;
	}

	/**
	 * 初始化ehcache插件
	 * 
	 * @param env
	 */
	private IPlugin initEhcachePlugin(Environment env) {
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.ehcache.");
		String inited = propertyResolver.getProperty("inited");
		if (!"true".equalsIgnoreCase(inited)) {
			return null;
		}
		GLog.debug("EhcachePlugin inited.");
		return new EhcachePlugin();
	}

	private IPlugin initSqlResourcePreloadPlugin(Environment env) {

		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.mirage.");
		String path = propertyResolver.getProperty("sqlpath");
		if (StrKit.isBlank(path)) {
			return null;
		}

		GLog.debug("SqlResourcePreloadPlugin inited.");
		String[] pathArray = path.split(",");
		List<String> pathList = Arrays.asList(pathArray);
		SqlResourcePreloadPlugin plugin = new SqlResourcePreloadPlugin(pathList);
		return plugin;
	}

	private IPlugin initTransactionPlugin(Environment env) {
		// TransactionIsolationPlugin
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.transaction.");
		String level = propertyResolver.getProperty("level");
		if (StrKit.isBlank(level)) {
			return null;
		}

		GLog.debug("TransactionIsolationPlugin inited.");
		int levelInt = Integer.parseInt(level);
		TransactionIsolationPlugin plugin = new TransactionIsolationPlugin(levelInt);
		return plugin;
	}
}
